using NHibernate;
using SmartHRMS.CustomExceptions.Infrastructure;
using SmartHRMS.Infrastructure;
using System;
using System.Collections.Generic;

namespace SmartHRMS.NhibernateRepository
{
    public abstract class BaseRepository<T> : IRepository<T> where T : IAggregateRoot
    {
        private IUnitOfWork _UnitOfWork;       

        public void Inject(Infrastructure.IUnitOfWork UnitOfWork)
        {
            _UnitOfWork = UnitOfWork;
        }
		
        public IList<T> FindAll()
        {
            NHibernate.ICriteria CriteriaQuery = SessionFactory.GetCurrentSession().CreateCriteria(typeof(T));
            return CriteriaQuery.List<T>();
        }

        public IList<T> FindBy(Infrastructure.Query.Query Query)
        {
            ICriteria criteria = SessionFactory.GetCurrentSession().CreateCriteria(typeof(T));
			
            return QueryTranslator.GetCriteriaFrom(criteria, Query).List<T>();
        }
		
        public T FindBy(Guid Id)
        {
            // Load doesn't return null if no entity found
            //Return NHSession.Load(Of T)(Id)
            return SessionFactory.GetCurrentSession().Get<T>(Id);
        }
		
        public void Remove(T Entity)
        {
            if (_UnitOfWork == null)
            {
                using (var Transaction = SessionFactory.GetCurrentSession().BeginTransaction())
                {
                    SessionFactory.GetCurrentSession().Delete(Entity);
                    try
                    {
                        Transaction.Commit();
                    }
                    catch (Exception)
                    {
                        Transaction.Rollback();
                        // TODO: Log exception
                        throw;
                    }
                }
            }
            else
            {
                _UnitOfWork.Delete(Entity);
            }
        }
		
        public void Save(T Entity)
        {
            if (_UnitOfWork == null)
            {
                using (var Transaction = SessionFactory.GetCurrentSession().BeginTransaction())
                {
                    SessionFactory.GetCurrentSession().SaveOrUpdate(Entity);
					
                    try
                    {
                        Transaction.Commit();
                    }
                    catch (NHibernate.StaleObjectStateException ex)
                    {
                        // Catch StaleObjectStateException:
                        // Entity was changed while we were viewing it,
                        // Wrap Nhibernate exception  and then send it
                        // back up the calling stack
                        throw (new ConcurrencyException(string.Format("Please reload the {0} as changes have been made to it since you have loaded it.", Entity.ToString()), ex));
                    }
                    catch (Exception)
                    {
                        Transaction.Rollback();
                        // TODO: Log exception
                        throw;
                    }
                }
            }
            else
            {
                _UnitOfWork.Save(Entity);
            }
        }
    }
}
